using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.WorkItemTracking;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Controls;
using C1.Win.C1FlexGrid;

namespace Hemi
{
    public partial class MapTypesStage : UserControl, IMoveStage
    {
        MoveStageState _state = MoveStageState.RequireUserInput;
        Dictionary<WorkItemType, WorkItemMoveInfoList> _srcWITMapping;
        Dictionary<string, WorkItemType> _targetWITMapping;

        Dictionary<string, Field> _totalMissingFields;
        Dictionary<string, WorkItemMoveInfoList> _workItemsWithMissingFields;

        ProgressDialog _progressDialog;

        string _invalidMessage;

        public MapTypesStage()
        {
            InitializeComponent();

            _progressDialog = new ProgressDialog();
            _progressDialog.StartPosition = FormStartPosition.CenterParent;
        }

        #region IMoveStage Members

        void IMoveStage.CommitChanges()
        {
            //
            // Nothing to do here since we don't actually commit any changes
            //
        }

        bool IMoveStage.CanTestValidate
        {
            get { return true; }
        }

        string IMoveStage.Name
        {
            get
            {
                return "Define Target Work Item Type";
            }
        }

        string IMoveStage.Description
        {
            get
            {
                return @"Please select what target Work Item Type you would like to 
move your work items to.  In most cases, the Work Item Type will be the same.  For 
example, if you are moving bugs, you would most likely select that as your target 
Work Item type.  Based on your choice, there may be fields in the target Work Item Type
that require your input.";
            }
        }

        string IMoveStage.InvalidMessage
        {
            get
            {
                return _invalidMessage;
            }
        }

        string IMoveStage.ValidMessage
        {
            get
            {
                return Properties.Resources.MissingFields_ValidMessage;
            }
        }

        MoveStageState IMoveStage.State
        {
            get { return _state; }
        }

        bool IMoveStage.Validate()
        {
            bool valid = true;
            StringBuilder builder = new StringBuilder();

            //
            // Make sure we've mapped all the required types
            //
            bool someEmpty = false;
            foreach (C1.Win.C1FlexGrid.Row row in _witFlex.Rows)
            {
                string targetWIT = row["targetWIT"] as string;

                if (targetWIT == null || targetWIT.Equals(string.Empty) || targetWIT.Equals(Properties.Resources.MapFields_TypePrompt))
                {
                    someEmpty = true;
                    break;
                }               
            }

            if (someEmpty)
            {
                builder.AppendLine("Please map all of your source Work Item Types to a target.");
                valid = false;
            }

            
            //
            // Make sure all the fields have been mapped
            //  
            if (_workItemsWithMissingFields == null)
            {
                valid = false;

                builder.AppendLine("Please press the 'Press for Missing Values' button to before continuing.");
            }
            else
            {
                foreach (WorkItemMoveInfoList workItems in _workItemsWithMissingFields.Values)
                {
                    foreach (WorkItemMoveInfo workItemCopy in workItems)
                    {
                        if (workItemCopy.Copy.Validate().Count > 0)
                        {
                            valid = false;
                            break;
                        }
                    }
                }
            }

            if (!valid)
            {
                builder.AppendLine("Please provide values for all of the target fields that require them.");
            }

            _invalidMessage = builder.ToString();

            return valid;
        }

        UserControl IMoveStage.UserControl
        {
            get
            {
                return this;
            }
        }

        #endregion

        private void MapTypesStage_Load(object sender, EventArgs e)
        {
            _typesBackgroundWorker.RunWorkerAsync();
            _progressDialog.ShowDialog();
        }

        private string WITAsList(Project project)
        {
            _targetWITMapping = new Dictionary<string, WorkItemType>();

            StringBuilder builder = new StringBuilder();
            
            foreach (WorkItemType wit in project.WorkItemTypes)
            {
                _targetWITMapping.Add(wit.Name, wit);

                builder.Append(wit.Name);
                builder.Append("|");
            }

            return builder.ToString();
        }

        private void _witFlex_AfterEdit(object sender, RowColEventArgs e)
        {
            //
            // Figure out what row was edited
            //
            C1.Win.C1FlexGrid.Row row = _witFlex.Rows[e.Row];

            WorkItemType type = (WorkItemType)row.UserData;

            WorkItemMoveInfoList list = _srcWITMapping[type];

            foreach (WorkItemMoveInfo workItem in list)
            {
                workItem.DestWIT = _targetWITMapping[(string)row["targetWIT"]];
            }
        }

        private void _witFlex_BeforeEdit(object sender, RowColEventArgs e)
        {
            //
            // The only column that we allow editing for is the target WIT
            //
            string value = (string)_witFlex[e.Row, e.Col];

            if (value.Equals(Properties.Resources.MapFields_TypePrompt))
            {
                _witFlex[e.Row, e.Col] = string.Empty;
            }                                
        }

        private void _checkForMissingValuesButton_Click(object sender, EventArgs e)
        {
            _progressDialog = new ProgressDialog();
            _progressDialog.StartPosition = FormStartPosition.CenterParent;

            _fieldsBackgroundWorker.RunWorkerAsync();
            _progressDialog.ShowDialog();
        }

        #region Map Types
        private void _typesBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //
            // Show all the types that we have
            //
            _srcWITMapping = new Dictionary<WorkItemType, WorkItemMoveInfoList>();

            string targetWITs = string.Empty;
            _typesBackgroundWorker.ReportProgress(50, "Correlating all Work Item Types being moved...");

            foreach (WorkItemMoveInfo workItem in HemiContextSingleton.Instance.WorkItemsToMove)
            {
                if (_srcWITMapping.ContainsKey(workItem.WorkItem.Type))
                {
                    WorkItemMoveInfoList list = _srcWITMapping[workItem.WorkItem.Type];

                    list.Add(workItem);
                }
                else
                {
                    WorkItemMoveInfoList list = new WorkItemMoveInfoList();
                    list.Add(workItem);

                    _srcWITMapping.Add(workItem.WorkItem.Type, list);
                }

                if (targetWITs.Equals(string.Empty))
                {
                    targetWITs = WITAsList(workItem.DestProject);
                }
            }

            _typesBackgroundWorker.ReportProgress(50, "Getting all available Work Item Types from target project...");
            _witFlex.Cols["targetWIT"].ComboList = targetWITs;
            foreach (WorkItemType type in _srcWITMapping.Keys)
            {
                C1.Win.C1FlexGrid.Row row = _witFlex.Rows.Add();

                row["srcWIT"] = type.Name;
                row.UserData = type;

                row["targetWIT"] = Properties.Resources.MapFields_TypePrompt;
            }        
        }

        private void _typesBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            SafeUpdateProgress(e);
        }

        private void _typesBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _progressDialog.Close();
        }
        #endregion

        #region Find Missing Fields
        private void _fieldsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            int totalNumber = HemiContextSingleton.Instance.WorkItemsToMove.Count;
            int oneIncrement = (1 / totalNumber) * 100;

            _fieldsBackgroundWorker.ReportProgress(oneIncrement, "Checking for missing fields...");

            //
            // Figure out what fields are missing
            //
            _workItemsWithMissingFields = new Dictionary<string, WorkItemMoveInfoList>();
            _totalMissingFields = new Dictionary<string, Field>();

            foreach (WorkItemMoveInfo workItemMoveInfo in HemiContextSingleton.Instance.WorkItemsToMove)
            {
                _fieldsBackgroundWorker.ReportProgress(oneIncrement, string.Format("Examining {0}", workItemMoveInfo.WorkItem.Title));

                System.Collections.ArrayList missingFields = workItemMoveInfo.CreateCopy();

                foreach (Field field in missingFields)
                {
                    if (!_totalMissingFields.ContainsKey(field.Name))
                    {
                        _totalMissingFields.Add(field.Name, field);

                        _workItemsWithMissingFields.Add(field.Name, new WorkItemMoveInfoList());
                        _workItemsWithMissingFields[field.Name].Add(workItemMoveInfo);
                    }
                    else
                    {
                        _workItemsWithMissingFields[field.Name].Add(workItemMoveInfo);
                    }
                }
            }

            Util.ClearRows(_fieldsFlex);

            if (_totalMissingFields.Count == 0)
            {
                _progressDialog.Close();
                MessageBox.Show(Properties.Resources.MissingFields_ValidMessage);
            }
            else
            {
                foreach (Field field in _totalMissingFields.Values)
                {
                    C1.Win.C1FlexGrid.Row row = _fieldsFlex.Rows.Add();

                    row["name"] = field.Name;
                    row["value"] = Properties.Resources.MissingFields_EmptyFieldValue;
                    row["required"] = field.IsRequired;

                    row.UserData = field;
                }
            }           
        }

        private void _fieldsBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            SafeUpdateProgress(e);
        }

        private void _fieldsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _progressDialog.Close();
        }
        #endregion

        private void _fieldsFlex_AfterEdit(object sender, RowColEventArgs e)
        {
            if (_fieldsFlex.Cols[e.Col].Name.Equals("value"))
            {
                C1.Win.C1FlexGrid.Row row = _fieldsFlex.Rows[e.Row];

                string value = row["value"] as string;

                if (value != null && !value.Equals(string.Empty))
                {
                    //
                    // After we edit a field, fill it in
                    //s
                    Field field = (Field)row.UserData;

                    WorkItemMoveInfoList workItems = _workItemsWithMissingFields[field.Name];

                    foreach (WorkItemMoveInfo workItem in workItems)
                    {
                        workItem.Copy.Fields[field.Name].Value = row["value"];
                    }
                }
                else
                {
                    row["value"] = Properties.Resources.MissingFields_EmptyFieldValue;
                }
            }
        }

        private void _fieldsFlex_BeforeEdit(object sender, RowColEventArgs e)
        {
            if (_fieldsFlex.Cols[e.Col].Name.Equals("value"))
            {
                C1.Win.C1FlexGrid.Row row = _fieldsFlex.Rows[e.Row];

                //
                // Determine what editor we should show for this field
                //                
                Field field = (Field)row.UserData;

                if (field.IsLimitedToAllowedValues)
                {
                    StringBuilder builder = new StringBuilder();

                    foreach (string value in field.AllowedValues)
                    {
                        builder.Append(value);
                        builder.Append("|");
                    }

                    row.ComboList = builder.ToString();
                }
                else
                {
                    if (row["value"].Equals(Properties.Resources.MissingFields_EmptyFieldValue))
                    {
                        row["value"] = string.Empty;
                    }
                }
            }
        }

        private void SafeUpdateProgress(ProgressChangedEventArgs e)
        {
            _progressDialog._progressLabel.Text = e.UserState.ToString();

            int potentialUpdate = _progressDialog._progressBar.Value + e.ProgressPercentage;
            if (potentialUpdate < 100)
            {
                _progressDialog._progressBar.Value += e.ProgressPercentage;
            }
        }
    }
}
